#include "MCPayoff.h"

//namespace userPayoff
//{
class VOLTARGET : public EQMCBase
{
    /* declare variables/functions */
    int nReturns, stkIndex;
    double p, R, cap, floor, weightSum, targetVol, low, high, perf, annFac, alpha, fundingRate;
    mutable vector<double> weights, bsk, yearFractions; //EDIT
    /* initialise variables */
public: //EDIT
    void initData()
    {
        nReturns = getInt("nReturns", -1);
        annFac = getDouble("annFac", 254.0);
        //weights = new double[nReturns]; bsk = new double[nObs + 1]; yearFractions = new double[nObs + 1];
        weights.resize(nReturns);  //EDIT
        bsk.resize(nObs + 1); //EDIT
        yearFractions.resize(nObs + 1); //EDIT
        alpha = getDouble("weightPower", 1.0 - 3.0 / (double)nReturns);
        weightSum = alpha;
        weights[0] = weightSum;
        for (int t = 1; t < nReturns; ++t)
        {
            weights[t] = alpha * weights[t - 1];
            weightSum += weights[t];
        }
        fundingRate = getDouble("fundingRate", 0.0);
        string dcb = getString("daycountBasis", "ACT365");
        for (int t = 1; t <= nObs; ++t)
        {
            yearFractions[t] = fundingRate != 0 ? yearFraction(t - 1, t, dcb) : 0.0;
        }
        targetVol = getDouble("target", 0.13);
        cap = getDouble("cap", 1.25);
        floor = getDouble("floor", 0.0);
        //if (Math.Abs(floor) > 1e-8) { throw new Exception(("Error: floor must be set to 0.0, not " + to_string(floor) + ", use strikeFactor instead").c_str()); }
        low = getDouble("lowerLimit", 0.97);
        high = getDouble("upperLimit", 1.03);
        p = getDouble("participation", 1.0);
        R = getDouble("redemptionCash", 0.0);
        for (int t = 1; t <= nObs; ++t)
        {
            if (isEvent(t, SCH1))
            {
                stkIndex = t - 1;
                if (stkIndex < nReturns) { throw new Exception("Error: sch1 is too early, not enough obs for 1st realised vol computation"); }
            }
        }
    }
    /* auxiliary function */
    double option(const double S) const
    {
        if (derivativeType == PUT) { return Math.Max(strikeFactor - S, 0.0); }
        if (derivativeType == CALL) { return Math.Max(S - strikeFactor, 0.0); }
        if (derivativeType == FWD) { return (S - strikeFactor); }
        //throw new Exception("Error: Invalid derivativeType!");
        return std::numeric_limits<double>::quiet_NaN();
    }
    /* define payout */
    double calcCorePayoffBi(const int trial, bool isPastPayoff) const;

    double run() const;

}; //EDIT
//}

